//
//  FieldObservationDB.m
//  Tazama NGO
//
//  Created by jsheriff on 3/4/11.
//  Copyright 2011 The MITRE Corporation. All rights reserved.
//

#import "FieldObservationDB.h"
#import "AppDelegate_iPhone.h"
#import "Notifications.h"
#import "FieldObservationComm.h"
#import <sqlite3.h>

static sqlite3_stmt *insert_statement = nil;

@implementation FieldObservationDB

@synthesize fieldObservationList;

static FieldObservationDB *sharedInstance = nil;

+ (FieldObservationDB *)sharedInstance
{
    if (sharedInstance == nil) {
        sharedInstance = [[super allocWithZone:NULL] init];
    }
    return sharedInstance;
}

+ (id)allocWithZone:(NSZone *)zone
{
    return [[self sharedInstance] retain];
}

- (id)init
{
    if ((self = [super init]))
	{
		fieldObservationList = [[NSMutableArray alloc] init];
    }
    return self;
}

- (id)copyWithZone:(NSZone *)zone
{
    return self;
}

- (id)retain
{
    return self;
}

- (NSUInteger)retainCount
{
    return NSUIntegerMax;  //denotes an object that cannot be released
}

- (oneway void)release
{
    //do nothing
}

- (id)autorelease
{
    return self;
}

-(void)insertInDatabase:(FieldObservation *)fieldObservation {
    if (databaseLock == nil) {
		databaseLock = [[NSLock alloc] init];
	}
	[databaseLock lock];
	sqlite3 *database;
	if (sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
        if (insert_statement == nil) {
            static char *sql = "INSERT INTO FieldObservation (uuid, messageId, latitude, longitude, immediateNeeds, observationText, severity, confidence, image) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)";
            if (sqlite3_prepare_v2(database, sql, -1, &insert_statement, NULL) != SQLITE_OK) {
                NSAssert1(0, @"Error: failed to prepare statement with message '%s'.", sqlite3_errmsg(database));
            }
        }
        
        NSString *uuid = NSMakeCollectable(CFUUIDCreateString(kCFAllocatorDefault, fieldObservation.uuid));
        sqlite3_bind_text(insert_statement, 1, [uuid UTF8String], -1, SQLITE_TRANSIENT);
        sqlite3_bind_text(insert_statement, 2, [fieldObservation.messageId UTF8String], -1, SQLITE_TRANSIENT);
        sqlite3_bind_double(insert_statement, 3, fieldObservation.location.latitude);
        sqlite3_bind_double(insert_statement, 4, fieldObservation.location.longitude);
        sqlite3_bind_text(insert_statement, 5, [fieldObservation.immediateNeeds UTF8String], -1, SQLITE_TRANSIENT);
        sqlite3_bind_text(insert_statement, 6, [fieldObservation.observationText UTF8String], -1, SQLITE_TRANSIENT);
        sqlite3_bind_text(insert_statement, 7, [fieldObservation.severity UTF8String], -1, SQLITE_TRANSIENT);
        sqlite3_bind_text(insert_statement, 8, [fieldObservation.confidence UTF8String], -1, SQLITE_TRANSIENT);
        if (fieldObservation.image != nil) {
            NSData *imageData = UIImagePNGRepresentation(fieldObservation.image);
            sqlite3_bind_blob(insert_statement, 9, [imageData bytes], [imageData length], SQLITE_TRANSIENT);
        }
        else {
            sqlite3_bind_blob(insert_statement, 9, nil, -1, NULL);
        }

        int success = sqlite3_step(insert_statement);
        // Because we want to reuse the statement, we "reset" it instead of "finalizing" it.
        sqlite3_reset(insert_statement);
        if (success == SQLITE_ERROR) {
            NSAssert1(0, @"Error: failed to insert into the database with message '%s'.", sqlite3_errmsg(database));
        } else {
            // SQLite provides a method which retrieves the value of the most recently auto-generated primary key sequence
            // in the database. To access this functionality, the table should have a column declared of type 
            // "INTEGER PRIMARY KEY"
            //primaryKey = sqlite3_last_insert_rowid(database);
        }
    }
    [databaseLock unlock];
}

-(void) addNewFieldObservation:(FieldObservation *)fieldObservation {
	[fieldObservationList addObject:fieldObservation];
    [self insertInDatabase:fieldObservation];
    
    [[FieldObservationComm sharedInstance] postFieldObservationToServer2:fieldObservation];
    
    [[NSNotificationCenter defaultCenter] postNotificationName:kFieldObservationDatabaseUpdateKey object:self userInfo:nil];		
}

- (FieldObservation *)getFieldObservationWithId:(CFUUIDRef)uuid {
	for (FieldObservation *fo in fieldObservationList) {
		if (CFEqual(fo.uuid, uuid)) {
            NSLog(@"Field Observation found");
            return fo;
        }
    }

    return nil;
}

-(void) initWithTestData {
	CLLocationCoordinate2D location;
	
	FieldObservation *fo1 = [[FieldObservation alloc] init];
	fo1.uuid = CFUUIDCreate(kCFAllocatorDefault);
	fo1.immediateNeeds = @"Water";
	fo1.observationText = @"Village with 12 families has been without clean water for 3 days";
	fo1.severity = @"high";
	fo1.confidence = @"high";
	
	location.latitude = 40.994;
	location.longitude = 29.901;
	fo1.location = location;
	
    [fieldObservationList addObject:fo1];
	[fo1 release];
	
	FieldObservation *fo2 = [[FieldObservation alloc] init];
	fo2.uuid = CFUUIDCreate(kCFAllocatorDefault);
	fo2.immediateNeeds = @"Shelter and Food";
	fo2.observationText = @"35 persons need shelter and food";
	fo2.severity = @"high";
	fo2.confidence = @"high";
	
	location.latitude = 40.848;
	location.longitude = 30.017;
	fo2.location = location;
	
    [fieldObservationList addObject:fo2];
	[fo2 release];
	
	FieldObservation *fo3 = [[FieldObservation alloc] init];
	fo3.uuid = CFUUIDCreate(kCFAllocatorDefault);
	fo3.immediateNeeds = @"Shelter";
	fo3.observationText = @"Village with 18 families has been without shelter for 3 days";
	fo3.severity = @"high";
	fo3.confidence = @"high";
	
	location.latitude = 40.873;
	location.longitude = 29.988;
	fo3.location = location;
	
    [fieldObservationList addObject:fo3];
	[fo3 release];
	
	FieldObservation *fo4 = [[FieldObservation alloc] init];
	fo4.uuid = CFUUIDCreate(kCFAllocatorDefault);
	fo4.immediateNeeds = @"Medicine";
	fo4.observationText = @"Clinic needs antibiotics";
	fo4.severity = @"high";
	fo4.confidence = @"high";
	
	location.latitude = 40.849;
	location.longitude = 29.920;
	fo4.location = location;
	
    [fieldObservationList addObject:fo4];
	[fo4 release];
	
	FieldObservation *fo5 = [[FieldObservation alloc] init];
	fo5.uuid = CFUUIDCreate(kCFAllocatorDefault);
	fo5.immediateNeeds = @"Road Damage";
	fo5.observationText = @"Road severly damaged, impassable";
	fo5.severity = @"high";
	fo5.confidence = @"high";
    
//    NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    fo5.image = [UIImage imageNamed:@"road.jpg"];
	
	location.latitude = 40.706;
	location.longitude = 30.019;
	fo5.location = location;
	
    [fieldObservationList addObject:fo5];
	[fo5 release];
	
	FieldObservation *fo6 = [[FieldObservation alloc] init];
	fo6.uuid = CFUUIDCreate(kCFAllocatorDefault);
	fo6.immediateNeeds = @"Food and Water";
    //	NSString *t = @"Test with lots of text....  water   water   water   water   water   water   water   water   water   water   water   water   water  ";
    //	fo6.observationText = [NSString stringWithFormat:@"%@ %@ %@ %@ %@ %@ %@ %@ %@ %@ %@ %@ %@ %@ %@ %@ %@ %@ %@ %@ ", t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t];
    fo6.observationText = @"Village with 14 families has been without clean water for 3 days.  Food is limited.";
	fo6.severity = @"high";
	fo6.confidence = @"high";
	
	location.latitude = 40.722;
	location.longitude = 29.953;
	fo6.location = location;
	
    [fieldObservationList addObject:fo6];
	[fo6 release];	
}

-(void) initWithTestDataLibya {
	CLLocationCoordinate2D location;
	
	FieldObservation *fo1 = [[FieldObservation alloc] init];
	fo1.uuid = CFUUIDCreate(kCFAllocatorDefault);
	fo1.immediateNeeds = @"Water";
	fo1.observationText = @"Village with 12 families has been without clean water for 3 days";
	fo1.severity = @"high";
	fo1.confidence = @"high";
	
	location.latitude = 31.994;
	location.longitude = 20.101;
	fo1.location = location;
	
    [fieldObservationList addObject:fo1];
	[fo1 release];
	
	FieldObservation *fo2 = [[FieldObservation alloc] init];
	fo2.uuid = CFUUIDCreate(kCFAllocatorDefault);
	fo2.immediateNeeds = @"Shelter and Food";
	fo2.observationText = @"35 persons need shelter and food";
	fo2.severity = @"high";
	fo2.confidence = @"high";
	
	location.latitude = 31.848;
	location.longitude = 20.017;
	fo2.location = location;
	
    [fieldObservationList addObject:fo2];
	[fo2 release];
	
	FieldObservation *fo3 = [[FieldObservation alloc] init];
	fo3.uuid = CFUUIDCreate(kCFAllocatorDefault);
	fo3.immediateNeeds = @"Shelter";
	fo3.observationText = @"Village with 18 families has been without shelter for 3 days";
	fo3.severity = @"high";
	fo3.confidence = @"high";
	
	location.latitude = 31.873;
	location.longitude = 20.188;
	fo3.location = location;
	
    [fieldObservationList addObject:fo3];
	[fo3 release];
	
	FieldObservation *fo4 = [[FieldObservation alloc] init];
	fo4.uuid = CFUUIDCreate(kCFAllocatorDefault);
	fo4.immediateNeeds = @"Medicine";
	fo4.observationText = @"Clinic needs antibiotics";
	fo4.severity = @"high";
	fo4.confidence = @"high";
	
	location.latitude = 31.849;
	location.longitude = 20.120;
	fo4.location = location;
	
    [fieldObservationList addObject:fo4];
	[fo4 release];
	
	FieldObservation *fo5 = [[FieldObservation alloc] init];
	fo5.uuid = CFUUIDCreate(kCFAllocatorDefault);
	fo5.immediateNeeds = @"Road Damage";
	fo5.observationText = @"Road severly damaged, impassable";
	fo5.severity = @"high";
	fo5.confidence = @"high";
    
    NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    fo5.image =[UIImage imageWithContentsOfFile: [NSString stringWithFormat:@"%@/%@", documentsDirectory, @"road.jpg"]];
	
	location.latitude = 31.706;
	location.longitude = 20.019;
	fo5.location = location;
	
    [fieldObservationList addObject:fo5];
	[fo5 release];
	
	FieldObservation *fo6 = [[FieldObservation alloc] init];
	fo6.uuid = CFUUIDCreate(kCFAllocatorDefault);
	fo6.immediateNeeds = @"Food and Water";
    //	NSString *t = @"Test with lots of text....  water   water   water   water   water   water   water   water   water   water   water   water   water  ";
    //	fo6.observationText = [NSString stringWithFormat:@"%@ %@ %@ %@ %@ %@ %@ %@ %@ %@ %@ %@ %@ %@ %@ %@ %@ %@ %@ %@ ", t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t];
    fo6.observationText = @"Village with 14 families has been without clean water for 3 days.  Food is limited.";
	fo6.severity = @"high";
	fo6.confidence = @"high";
	
	location.latitude = 31.722;
	location.longitude = 20.153;
	fo6.location = location;
	
    [fieldObservationList addObject:fo6];
	[fo6 release];	
}

-(void) initFromPath:(NSString *)path
{
    if (databaseLock == nil) {
		databaseLock = [[NSLock alloc] init];
	}
	[databaseLock lock];
	sqlite3 *database;
	if (sqlite3_open([path UTF8String], &database) == SQLITE_OK) {
		NSString *query = @"select uuid, messageId, latitude, longitude, immediateNeeds, observationText, severity, confidence, image from FieldObservation";
		sqlite3_stmt *statement;
		int resultPrepare = sqlite3_prepare_v2(database, [query UTF8String], -1, &statement, nil);
		if (resultPrepare == SQLITE_OK) {
			while (sqlite3_step(statement) == SQLITE_ROW) {
                FieldObservation *fo = [[FieldObservation alloc] init];
                CLLocationCoordinate2D location;

				NSString *uuid = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 0)];
                fo.uuid = CFUUIDCreateFromString(kCFAllocatorDefault, (CFStringRef)uuid);
                fo.messageId = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 1)];
                location.latitude = sqlite3_column_double(statement, 2);
                location.longitude = sqlite3_column_double(statement, 3);
                fo.location = location;
                fo.immediateNeeds = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 4)];
                fo.observationText = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 5)];
                fo.severity = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 6)];
                fo.confidence = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 7)];
                NSData *data = [[NSData alloc] initWithBytes:sqlite3_column_blob(statement, 8) length:sqlite3_column_bytes(statement, 8)];
                if (data == nil) {
                    NSLog(@"No FieldObservation image found.");
                }
                else {
                    fo.image = [UIImage imageWithData:data];
                }
                [data release];
                
                fo.messageSent = YES;
                
                [fieldObservationList addObject:fo];
                [fo release];	
            }            
		}
		else {
			//
			NSLog(@"Unable to prepare statement");
		}
		sqlite3_close(database);
        databasePath = path;
        [databasePath retain];
	}
    
	[databaseLock unlock];
}

@end
